home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 37 / Amiga Format CD37 (1999-02-16)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-03].iso / -screenplay- / shareware / invasionforce / source / data_struct.c < prev    next >
C/C++ Source or Header  |  1999-01-09  |  16KB  |  569 lines

  1. /*
  2.    data_struct.c -- universal data structures for Invasion Force
  3.    This module defines and declares major global data structures.
  4.    This source code is free.  You may make as many copies as you like.
  5. */
  6.  
  7. #include "global.h"
  8.  
  9. // *** following are globals used by both the map editor and the game
  10. int width, height; // current map size
  11. int xoffs, yoffs;  // current map offsets
  12. BOOL wrap;           // flag for wrap-around map
  13. UBYTE *t_grid = NULL;   // grid storage for basic terrain map
  14. UBYTE *me_grid = NULL;
  15. struct MinList city_list;  // the universal city list
  16.  
  17. char default_city_name[] = "Metropolis";
  18.  
  19. // this array holds a list of hexagon coordinates for use by
  20. // functions like adjacent() and such
  21. struct Hex_Coords hexlist[64];
  22.  
  23.  
  24. char *terrain_name_table[] = {
  25.    "Unexplored",
  26.    "Plains",
  27.    "Desert",
  28.    "Forbidden",
  29.    "Scrubland",
  30.    "Forest",
  31.    "Jungle",
  32.    "Rugged",
  33.    "Hills",
  34.    "Mountains",
  35.    "Mountain Peaks",
  36.    "Swamp",
  37.    "Shallow Waters",
  38.    "Ocean",
  39.    "Deep Ocean",
  40.    "Packed Ice",
  41.    "City",
  42.    "Roads"
  43. };
  44.  
  45.  
  46. /*
  47.    The movement_cost[] chart holds the movement cost for each type of
  48.    unit on each type of terrain.  This will allow me to customize the
  49.    movement characteristics of each unit type however I desire!
  50. */
  51.  
  52. short movement_cost_table[12][16] = {
  53.    /* RIFLE */
  54.    { 75, 60, 60, -1, 60, 70, 90, 60, 70, 80, -1, 90, -1, -1, -1, -1 },
  55.    /* ARMOR */
  56.    { 90, 60, 60, -1, 60, 90, 150,70, 90, -1, -1, -1, -1, -1, -1, -1 },
  57.    /* AIRCAV */
  58.    { 60, 60, 60, -1, 60, 60, 60, 60, 60, 60, -1, 60, 60, 60, 60, 60 },
  59.    /* BOMBER */
  60.    { 60, 60, 60, -1, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 },
  61.    /* FIGHTER */
  62.    { 60, 60, 60, -1, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 },
  63.    /* TRANSPORT */
  64.    { 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 60, 60, -1 },
  65.    /* SUB */
  66.    { 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 60, 60, -1 },
  67.    /* DESTROYER */
  68.    { 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 60, 60, -1 },
  69.    /* CRUISER */
  70.    { 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 60, 60, -1 },
  71.    /* BATTLESHIP */
  72.    { 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 60, 60, -1 },
  73.    /* CARRIER */
  74.    { 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 80, 60, 60, -1 },
  75.    /* AIRBASE */
  76.    { 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }
  77. };
  78.  
  79.  
  80.  
  81. struct UnitTemplate wishbook[] = {
  82.       {RIFLE,250,-1,60,1,TRUE,FALSE,"Infantry"},
  83.       {ARMOR,500,-1,120,2,FALSE,FALSE,"Armor"},
  84.       {AIRCAV,700,12,180,1,FALSE,FALSE,"Air Cavalry"},
  85.       {BOMBER,500,24,240,1,FALSE,FALSE,"Bomber"},
  86.       {FIGHTER,500,18,360,1,TRUE,FALSE,"Fighter"},
  87.       {TRANSPORT,1250,-1,120,3,TRUE,TRUE,"Transport"},
  88.       {SUB,1000,-1,120,2,TRUE,TRUE,"Submarine"},
  89.       {DESTROYER,1000,-1,180,3,TRUE,TRUE,"Destroyer"},
  90.       {CRUISER,1500,-1,120,8,TRUE,TRUE,"Cruiser"},
  91.       {BATTLESHIP,2500,-1,120,12,TRUE,TRUE,"Battleship"},
  92.       {CARRIER,2000,-1,120,8,TRUE,TRUE,"Carrier"},
  93.       {AIRBASE,100000,-1,0,1,TRUE,FALSE,"Airbase"}
  94. };
  95.  
  96. struct InfoTemplate infostatus[] = {
  97.       {FALSE},
  98.       {FALSE},
  99.       {FALSE},
  100.       {FALSE},
  101.       {FALSE},
  102.       {FALSE},
  103.       {FALSE},
  104.       {FALSE},
  105.       {FALSE},
  106.       {FALSE},
  107.       {FALSE},
  108. };
  109.  
  110.  
  111. /*
  112.    Because of the way the game evolved historically, it stores map data in
  113.    a rather odd format.  The terrain is stored in a grid, one nybble per
  114.    hex.  The flag data (roads, mines, etc.) follows immedately in a second
  115.    grid of the same size, again one nybble per hex.  Thus, to access the
  116.    flags for a given hex, it must first calculate the size of the whole
  117.    terrain data area and skip over that.  This process should be invisible
  118.    to the rest of the program, as long as it accesses all the map data
  119.    through these functions.
  120. */
  121.  
  122.  
  123. void put(grid,x,y,value)
  124. UBYTE *grid;
  125. int x, y, value;
  126. {  // put a 4-bit value (0-15) into a map grid position
  127.    int twd;
  128.    UBYTE *bptr;
  129.  
  130.    wrap_coords(&x,&y);
  131.  
  132.    twd = (width+width%2)/2;            // true byte-width of the map
  133.    bptr = grid+y*twd+(int)((x+1)/2);   // find the relevent byte
  134.  
  135.    if (x%2)
  136.       *bptr = (*bptr & 0xF0) | value;  // clear and store low nybble
  137.    else
  138.       *bptr = (*bptr & 0x0F) | (value<<4);   // clear and store high nybble
  139. }
  140.  
  141.  
  142. void put_flags(grid,x,y,value)
  143. UBYTE *grid;
  144. int x, y, value;
  145. {  // put a 4-bit flags value (0-15) into a map grid position
  146.    int twd;
  147.    UBYTE *bptr;
  148.  
  149.    wrap_coords(&x,&y);
  150.  
  151.    twd = (width+width%2)/2;            // true byte-width of the map
  152.    bptr = (grid+y*twd+(int)((x+1)/2))+GRID_SIZE;   // find the relevent byte
  153.  
  154.    if (x%2)
  155.       *bptr = (*bptr & 0xF0) | value;  // clear and store low nybble
  156.    else
  157.       *bptr = (*bptr & 0x0F) | (value<<4);   // clear and store high nybble
  158. }
  159.  
  160.  
  161. // get a 4-bit value (0-15) from a map position
  162.  
  163. int get(grid,x,y)
  164. UBYTE *grid;
  165. int x, y;
  166. {
  167.    int twd;
  168.    UBYTE *bptr;
  169.  
  170.    if (!VALID_HEX(x,y))
  171.       return HEX_UNEXPLORED;
  172.    twd = (width+width%2)/2;   // true byte-width of the map
  173.    bptr = grid+y*twd+(int)((x+1)/2);   // find the relevent byte
  174.    if (x%2)
  175.       return (*bptr & 0x0F);  // get low nybble
  176.    else
  177.       return ((*bptr & 0xF0)>>4);      // get high nybble
  178. }
  179.  
  180.  
  181. // get a 4-bit flags value (0-15) from a map position
  182.  
  183. int get_flags(grid,x,y)
  184. UBYTE *grid;
  185. int x, y;
  186. {
  187.    int twd;
  188.    UBYTE *bptr;
  189.  
  190.    if (!VALID_HEX(x,y))
  191.       return HEX_UNEXPLORED;
  192.    twd = (width+width%2)/2;   // true byte-width of the map
  193.    bptr = (grid+y*twd+(int)((x+1)/2))+GRID_SIZE;   // find the relevent byte
  194.    if (x%2)
  195.       return (*bptr & 0x0F);  // get low nybble
  196.    else
  197.       return ((*bptr & 0xF0)>>4);      // get high nybble
  198. }
  199.  
  200.  
  201. /*
  202.    free_map() checks to see if the given map grid is active (i.e. non-zero),
  203.    and, if so, will free the RAM and zero the grid pointer
  204.  
  205.    I tried to do this differently, so I didn't have to give free_map() a pointer
  206.    to a pointer, but it turned out to be an awful lot of work.  These functions
  207.    [both free_map() and alloc_map()] are smart functions.  Leave the smarts in
  208.    them.  Smart is good.
  209. */
  210.  
  211. VOID free_map(grid)
  212. UBYTE **grid;  // location of a pointer to a map grid
  213. {
  214.    if (*grid) {         // if *grid is non-zero, I assume it's been allocated
  215.       FreeVec(*grid);   // so I de-allocate it
  216.       *grid = NULL;     // when free_map() exits, *grid will always be NULL
  217.    FI
  218. }
  219.  
  220.  
  221. /*
  222.    alloc_map() takes the specified map grid, zeroes and clears it if necessary
  223.    [using free_map()], then allocates a new map grid, calculating the size of the
  224.    required RAM block based on the current map size values  [see additional
  225.    comments with free_map()]
  226. */
  227.  
  228. BOOL alloc_map(grid)
  229. UBYTE **grid;
  230. {
  231.    UBYTE *newgrid;
  232.  
  233.    free_map(grid);   // clear and zero any old map grid from this space
  234.    newgrid = AllocVec(GRID_SIZE*2,MEMF_CLEAR);
  235.    if (newgrid) {
  236.       *grid = newgrid;
  237.       return TRUE;
  238.    } else {    // assume a non-fatal error,
  239.       // though the calling function can still do a fatality if it wants to
  240.       alarm("Insufficient RAM for map!\n");
  241.       return FALSE;
  242.    FI
  243. }
  244.  
  245.  
  246. // flood the map with a single value (terrain type)
  247.  
  248. void flood_map(grid,value)
  249. UBYTE *grid;
  250. int value;
  251. {
  252.    int flag = 0;
  253.    int xc, yc;
  254.  
  255.    for (yc=0; yc<height; yc++)
  256.       for (xc=0; xc<width; xc++) {
  257.          flag = get_flags(grid,xc,yc);
  258.          if (flag) {
  259.                 flag = flag & (~ROAD);  // remove roads
  260.                 put_flags(grid,xc,yc,flag);
  261.          FI
  262.          put(grid,xc,yc,value);
  263.       }
  264.       nuke_list(&city_list);
  265. }
  266.  
  267. void int_grid(grid,value)
  268. UBYTE *grid;
  269. int value;
  270. {
  271.    int xc, yc;
  272.  
  273.    for (yc=0; yc<height; yc++)
  274.       for (xc=0; xc<width; xc++)
  275.          put(grid,xc,yc,value);
  276. }
  277.  
  278. void clear_orders(unit)
  279. struct Unit *unit;
  280. {
  281.    if (unit->orders)
  282.       FreeVec(unit->orders);
  283.    unit->orders = NULL;
  284. }
  285.  
  286.  
  287. void destruct_unit(unit)
  288. struct Unit *unit;
  289. {  // destroy a unit, freeing all RAM associated with it
  290.    if (unit->orders)
  291.       FreeVec(unit->orders);
  292.    if (unit->name)
  293.       FreeVec(unit->name);
  294.    FreeVec(unit);
  295. }
  296.  
  297.  
  298. char *random_name(utype)
  299. int utype;  // the type of unit we are naming
  300. {
  301.    static char name[20];
  302.    BOOL ship=wishbook[utype].ship_flag;
  303.    int ctr=0;
  304.    struct Unit *unit;
  305.    BOOL found;
  306.  
  307.    strcpy(name,"UNNAMED");
  308.    if (ship) {
  309.       /*
  310.          filename = name of the data file I'm reading names from
  311.          flen = length of the data file
  312.          nrecs = number of records in the file
  313.          chosen = number of the record I have chosen randomly
  314.          rsz = record size (currently 20)
  315.       */
  316.       char filename[128];
  317.       BPTR infile;
  318.       int flen, nrecs, chosen;
  319.       long rsz=20L;  // record size
  320.  
  321.       strcpy(filename,"progdir:data/NAMES.");
  322.       strcat(filename,wishbook[utype].name);
  323.       flen = FLength(filename);
  324.       if (flen<rsz)
  325.          return name;
  326.       nrecs = flen/rsz;
  327.       do {
  328.          // chose a name randomly and read it
  329.          chosen = RangeRand(nrecs);
  330.          infile = Open(filename,MODE_OLDFILE);
  331.          if (infile==NULL)
  332.             return name;
  333.          Seek(infile,chosen*rsz,OFFSET_BEGINNING);
  334.          Read(infile,name,rsz);
  335.          Close(infile);
  336.          name[19]='\0'; // just in case the name is 19 characters long
  337.          ctr++;
  338.  
  339.          // see if this name has already been used
  340.          found = FALSE;
  341.          for (unit=(struct Unit *)unit_list.mlh_Head;unit->unode.mln_Succ;unit=(struct Unit *)unit->unode.mln_Succ)
  342.             if (unit->name)
  343.                if (strcmp(name,unit->name)==0) {
  344.                   found = TRUE;
  345.                   break;
  346.                FI
  347.       } while (found && ctr<=10);
  348.    } else {    // it's not a ship, so we must generate a name
  349.       int number;
  350.       char template[8];
  351.  
  352.       do {
  353.          // random name
  354.          strcpy(template,"%ldth");
  355.          number = RangeRand(999)+1;    // range from 1-999
  356.          if (number<4 || number>20)
  357.             switch(number%10) {
  358.                case 1:
  359.                   strcpy(template,"%ldst");
  360.                   break;
  361.                case 2:
  362.                   strcpy(template,"%ldnd");
  363.                   break;
  364.                case 3:
  365.                   strcpy(template,"%ldrd");
  366.                   break;
  367.             }
  368.          sprintf(name,template,number);
  369.  
  370.          // see if this name has already been used
  371.          // it only counts as a dupe if it's the same type and same owner
  372.          found = FALSE;
  373.          for (unit=(struct Unit *)unit_list.mlh_Head;unit->unode.mln_Succ;unit=(struct Unit *)unit->unode.mln_Succ)
  374.             if (unit->name)
  375.                if (strcmp(name,unit->name)==0 && unit->type==utype && unit->owner==player) {
  376.                      found = TRUE;
  377.                      break;
  378.                FI
  379.       } while (found && ctr<=10);
  380.    FI
  381.    return name;
  382. }
  383.  
  384.  
  385. // set the name of a unit to a specified string value
  386. void name_unit(unit,name)
  387. struct Unit *unit;
  388. char *name;
  389. {
  390.    if (unit->name)   // destruct any name it might already have
  391.       FreeVec(unit->name);
  392.  
  393.    // allocate memory for name and copy new text into it
  394.    unit->name = AllocVec(strlen(name)+1,MEMF_CLEAR);
  395.    if (unit->name)
  396.       strcpy(unit->name,name);
  397. }
  398.  
  399.  
  400. // *** following are list functions
  401. //     they are all designed to work with MinList and MinNode structures
  402.  
  403. BOOL emptylistP(the_list)
  404. struct MinList *the_list;
  405. {  // is this list empty?
  406.    return (BOOL)(the_list->mlh_TailPred==(struct MinNode *)the_list);
  407. }
  408.  
  409. void nuke_list(ground_zero)
  410. struct MinList *ground_zero;
  411. {  // wipe out contents of list, free all memory
  412.    struct MinNode *casualty;
  413.  
  414.    // the list may never have been initialized
  415.    if (ground_zero->mlh_Head==NULL)
  416.       return;
  417.  
  418.    // de-allocate each node using FreeVec()
  419.    // This way we can destroy large structures
  420.    // without even knowing what they are!
  421.    while (!emptylistP(ground_zero)) {
  422.       casualty = ground_zero->mlh_Head;
  423.       RemHead((struct List *)ground_zero);   // decapitated!!
  424.       FreeVec(casualty);   // now dispose of the body
  425.    }
  426. }
  427.  
  428.  
  429. void nuke_units(ground_zero)
  430. struct MinList *ground_zero;
  431. {  // wipe out contents of unit list, free all memory
  432.    struct Unit *casualty;
  433.  
  434.    // the list may never have been initialized
  435.    if (ground_zero->mlh_Head==NULL)
  436.       return;
  437.  
  438.    // de-allocate each node and subitems using FreeVec()
  439.    while (!emptylistP(ground_zero)) {
  440.       casualty = (struct Unit *)ground_zero->mlh_Head;
  441.       RemHead((struct List *)ground_zero);
  442.       if (casualty->name)
  443.          FreeVec(casualty->name);
  444.       if (casualty->orders)
  445.          FreeVec(casualty->orders);
  446.       FreeVec(casualty);
  447.    OD
  448. }
  449.  
  450.  
  451. int count_nodes(list)
  452. struct MinList *list;
  453. {  // count nodes in the list, natch
  454.    struct MinNode *node = list->mlh_Head;
  455.    int ctr = 0;
  456.  
  457.    for ( ; node->mln_Succ; node = node->mln_Succ)
  458.       ctr++;
  459.    return ctr;
  460. }
  461.  
  462.  
  463. // *** following are city handling functions
  464.  
  465. struct City *city_hereP(col,row)
  466. int col, row;
  467. {  // is there a city here?  return the address
  468.    struct City *metro = (struct City *)city_list.mlh_Head;
  469.  
  470.    wrap_coords(&col,&row);
  471.  
  472.    for ( ; metro->cnode.mln_Succ; metro = (struct City *)metro->cnode.mln_Succ)
  473.       if (metro->col==col && metro->row==row)
  474.          return metro;
  475.    return NULL;
  476. }
  477.  
  478.  
  479. void create_city(col,row)
  480. int col, row;
  481. {  // attempt to make a city at the specified location
  482.    struct City *tcity = AllocVec((long)sizeof(*tcity),MEMF_CLEAR);
  483.    int ctr;
  484.  
  485.    wrap_coords(&col,&row);
  486.  
  487.    if (tcity) {
  488.       tcity->col = col;
  489.       tcity->row = row;
  490.       tcity->industry = 50;
  491.       tcity->specialty = CITY;   // by default, no specialty
  492.       strncpy(tcity->name,default_city_name,19);
  493.       for (ctr=0;ctr<9;ctr++)
  494.          tcity->recon[ctr] = CITY;
  495.       AddTail((struct List *)&city_list,(struct Node *)tcity);
  496.    FI
  497. }
  498.  
  499. void remove_city(col,row)
  500. int col, row;
  501. {
  502.    struct City *metro = (struct City *)city_list.mlh_Head;
  503.  
  504.    wrap_coords(&col,&row);
  505.  
  506.    for ( ; metro->cnode.mln_Succ; metro=(struct City *)metro->cnode.mln_Succ)
  507.       if (metro->col==col && metro->row==row) {
  508.          Remove((struct Node *)metro);
  509.          FreeVec(metro);
  510.          remove_city(col,row);  // in case there are more of them!
  511.          break;
  512.       FI
  513. }
  514.  
  515.  
  516. /*
  517.    This function, adjacent(), accepts the coordinates of a hex, then fills
  518.    the global array hexlist[] with coordinates of hexes ajacent to the original.
  519.    This makes dealing with the hexagon based map much easier.  It returns
  520.    the number of adjacent hexes actually found (usually six, sometimes less).
  521. */
  522.  
  523. int adjacent(col,row)
  524. int col, row;
  525. {
  526.    int even_offsets[12] = {-1,0, 1,0,  0,-1, -1,-1, 0,1, -1,1},
  527.        odd_offsets[12]  = {-1,0, 1,0,  1,-1, 0,-1,  1,1, 0,1};
  528.    int *table = (row%2) ? odd_offsets : even_offsets;
  529.    int x, y, ctr=0, index=0;
  530.  
  531.    // first zero out my global hexlist[] array
  532.    // actually, I'll use -1 instead of 0, because 0,0 might be valid
  533.    for (; ctr<8; ctr++) {
  534.       hexlist[ctr].col = -1;
  535.       hexlist[ctr].row = -1;
  536.    OD
  537.  
  538.    for (ctr=0; ctr<6; ctr++) {
  539.       x = col+table[ctr*2];   y = row+table[ctr*2+1];
  540.       wrap_coords(&x,&y);
  541.       if (x>=0 && x<width && y>=0 && y<height) {
  542.          hexlist[index].col = x;
  543.          hexlist[index++].row = y;
  544.       FI
  545.    OD
  546.    return index;
  547. }
  548.  
  549.  
  550. // This will tell me if it's a port city, so I can build ships there.
  551.  
  552. BOOL port_cityP(metro)
  553. struct City *metro;
  554. {
  555.    int num_hexes = adjacent(metro->col,metro->row);
  556.    int ctr=0;
  557.  
  558.    for (; ctr<num_hexes; ctr++)
  559.       switch (get(t_grid,hexlist[ctr].col,hexlist[ctr].row)) {
  560.          case HEX_SHALLOWS:
  561.          case HEX_OCEAN:
  562.          case HEX_DEPTH:
  563.             return TRUE;
  564.       }
  565.    return FALSE;
  566. }
  567.  
  568. // end of listing
  569.